package hr.pzrinscak.web;

import hr.pzrinscak.jpa.VacationRequest;
import hr.pzrinscak.service.UtilService;
import hr.pzrinscak.util.StaticUtils;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.FormService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.identity.User;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class TaskController {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    IdentityService identityService;

    @Autowired
    FormService formService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private UtilService utilService;

    @RequestMapping(value = "/task/list", method = RequestMethod.GET)
    @ResponseBody
    Map<String, Object> getTaskList(
            @RequestParam final int start,
            @RequestParam final int limit,
            @RequestParam(required=false) final String sort,
            @RequestParam(required=false) final String dir,
            @RequestParam final String condition) {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String userId = authentication.getName();

        TaskQuery taskQuery;

        if ("assigned".equals(condition)) {
            taskQuery = taskService.createTaskQuery().taskAssignee(userId);
        }
        else if ("unassigned".equals(condition)) {
            taskQuery = taskService.createTaskQuery().taskCandidateUser(userId);
        }
        else {
            taskQuery = taskService.createTaskQuery().taskCandidateGroup(condition);
        }

        if (StringUtils.hasText(sort)) {
            if ("taskStartDate".equals(sort)) {
                taskQuery.orderByTaskCreateTime();
            }
            else if ("taskDueDate".equals(sort)) {
                taskQuery.orderByDueDate();
            }
            else if ("taskName".equals(sort)) {
                taskQuery.orderByTaskName();
            }
            else if ("taskDescription".equals(sort)) {
                taskQuery.orderByTaskDescription();
            }

            if ("ASC".equals(dir)) {
                taskQuery.asc();
            }
            else if ("DESC".equals(dir)){
                taskQuery.desc();
            }
        }
        List<Task> userTasks = taskQuery.listPage(start, limit);
        long total = taskQuery.count();

        List<Map<String, Object>> taskList = generateTaskListMap(userTasks);

        Map<String, Object> response = new HashMap<String, Object>(2);
        response.put("totalCount", total);
        response.put("tasks", taskList);

        return response;
    }

    @RequestMapping(value = "/task/claim", method = RequestMethod.POST)
    @ResponseBody
    Map<String, Object> taskClaim(@RequestParam final String taskId) {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String userId = authentication.getName();

        taskService.claim(taskId, userId);

        Map<String, Object> response = new HashMap<String, Object>(2);
        response.put("success", true);
        response.put("message", "");
        return response;
    }

    @RequestMapping(value = "/task/form", method = RequestMethod.GET)
    ModelAndView getTaskForm(@RequestParam final String taskId) {

        TaskFormData formData = formService.getTaskFormData(taskId);
//        List<FormProperty> formPropertyList = formData.getFormProperties();
//        Map<String,Object> formPropertyMap = utilService.getParametersMapFromTask(formPropertyList);
        ModelAndView mav = new ModelAndView("process/" + formData.getFormKey());
        mav.addObject("data", taskService.getVariables(taskId));
        return mav;
    }

    @RequestMapping(value = "/task/form", method = RequestMethod.POST)
    @ResponseBody
    Map<String, Object> submitTaskForm(@ModelAttribute("package") final VacationRequest vacationRequest, @RequestParam final Map<String, Object> requestParameters) {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        requestParameters.put(StaticUtils.VARIABLE_ASSIGNED_BY, authentication.getName());
        String taskId = (String)requestParameters.remove("taskId");
        
        VacationRequest vacationRequestVariable = (VacationRequest)taskService.getVariable(taskId, "package");
        vacationRequestVariable.setManagerMotivation(vacationRequest.getManagerMotivation());
        vacationRequestVariable.setVacationApproved(vacationRequest.getVacationApproved());

        Map<String,Object> variables = new HashMap<String, Object>();
        variables.put("package.vacationApproved", vacationRequest.getVacationApproved());
        taskService.complete(taskId, variables);

        //formService.submitTaskFormData(taskId, requestParameters);

        Map<String, Object> response = new HashMap<String, Object>(2);
        response.put("success", true);
        response.put("message", "Submit success!");

        return response;
    }

//    @RequestMapping(value = "/task/list/unassigned", method = RequestMethod.GET)
//    @ResponseBody
//    Map<String, Object> getUnassignedTasks(@RequestParam final int start, @RequestParam final int limit) {
//
//        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//        String userId = authentication.getName();
//
//        TaskQuery taskQuery = taskService.createTaskQuery().taskCandidateUser(userId);
//        List<Task> userTasks = taskQuery.listPage(start, limit);
//        long total = taskQuery.count();
//
//        List<Map<String, Object>> taskList = generateTaskListMap(userTasks);
//
//        Map<String, Object> response = new HashMap<String, Object>(2);
//        response.put("totalCount", total);
//        response.put("tasks", taskList);
//
//        return response;
//    }
//
//    @RequestMapping(value = "/task/list/${candidateGroupId}", method = RequestMethod.GET)
//    @ResponseBody
//    Map<String, Object> getGroupTasks(@RequestParam final int start, @RequestParam final int limit, @PathVariable final String candidateGroupId) {
//
//        TaskQuery taskQuery = taskService.createTaskQuery().taskCandidateGroup(candidateGroupId);
//        List<Task> userTasks = taskQuery.listPage(start, limit);
//        long total = taskQuery.count();
//
//        List<Map<String, Object>> taskList = generateTaskListMap(userTasks);
//
//        Map<String, Object> response = new HashMap<String, Object>(2);
//        response.put("totalCount", total);
//        response.put("tasks", taskList);
//
//        return response;
//    }

    private List<Map<String, Object>> generateTaskListMap(final List<Task> taskList) {

        List<Map<String, Object>> returnTaskList = new ArrayList<Map<String,Object>>(taskList.size());
        for (Task task : taskList) {
            Map<String, Object> taskMap = new HashMap<String, Object>();
            taskMap.put("processInstanceId", task.getProcessInstanceId());
            taskMap.put("processDefinitionId", task.getProcessDefinitionId());
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
            taskMap.put("processName", processDefinition.getName());
            taskMap.put("taskId", task.getId());
            taskMap.put("taskName", task.getName());
            SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm");
            taskMap.put("taskStartDate", sdf.format(task.getCreateTime()));
            taskMap.put("taskDueDate", task.getDueDate() != null ? sdf.format(task.getDueDate()) : "");
            taskMap.put("taskDescription", task.getDescription());
            taskMap.put("taskFormKey", formService.getTaskFormData(task.getId()).getFormKey());
            taskMap.put("taskAssignee", task.getAssignee());
            taskMap.put("taskOwner", task.getOwner());
            Map <String, Object> variablesLocal = runtimeService.getVariablesLocal(task.getExecutionId());
            taskMap.putAll(variablesLocal);
            String assigned_by = (String)variablesLocal.get(StaticUtils.VARIABLE_ASSIGNED_BY);
            if (StringUtils.hasText(assigned_by)) {
                User assigned_byUser = identityService.createUserQuery().userId(assigned_by).singleResult();
                taskMap.put(StaticUtils.VARIABLE_ASSIGNED_BY, assigned_byUser.getFirstName() + " " + assigned_byUser.getLastName());
            }
            returnTaskList.add(taskMap);
        }
        return returnTaskList;
    }

}
